/*================================================================*
        Copyright (C) 2021 All rights reserved, www.hsby.link.
      	文件名称：tcp_server.cc
      	创 建 者：汉森伯逸
      	创建日期：2021/12/26
 *================================================================*/
#include "tcp_server.h"
#include "config.h"
#include "util/util.h"

static hsby::ConfigVar<int64_t>::Ptr g_tcp_server_read_timeout =
        hsby::Config::Lookup<int64_t>("tcp_server.read.read_timeout",
                             (int64_t)(60 * 1000 * 2),
                             "tcp server read timeout");

namespace hsby {

TcpServer::TcpServer(const std::string& name)
        : name_(name)
        , worker_(nullptr)
        , io_worker_(nullptr)
        , accept_worker_(nullptr)
        , read_timeout_(g_tcp_server_read_timeout->GetValue())
        , is_stop_(true)
        , ssl_(false){
}

TcpServer::Ptr TcpServer::Create(const std::string &name) {
    return hsby::TcpServer::Ptr(new TcpServer(name));
}

TcpServer::~TcpServer() {
    for (const auto& it : sockets_) {
        it->Close();
    }
    sockets_.clear();
}

void TcpServer::Dump(std::ostream &os) const {
    if (!is_init_) {
        os << "TcpServer no init";
        return;
    }
    os << "TcpServer{" << HSBY_VARS_EXP(type_, name_, ssl_, worker_->GetName(), accept_worker_->GetName(), read_timeout_);
    os << "\"sockets\":[";
    for (auto& socket : sockets_) {
        os << "{" << "socket:" << *socket << "},";
    }
    os << "]}";
}

bool TcpServer::Init(IoManager *worker, IoManager *io_worker, IoManager *accept_worker) {
    if (!worker || !io_worker || !accept_worker) {
        return false;
    }
    worker_ = worker;
    io_worker_ = io_worker;
    accept_worker_ = accept_worker;
    SetIsInit(true);
    return true;
}

bool TcpServer::Bind(BaseAddress::Ptr address) {
    std::vector<BaseAddress::Ptr> addrs;
    std::vector<BaseAddress::Ptr> fails;
    addrs.push_back(address);
    return Bind(addrs, fails);
}

bool TcpServer::Bind(const std::vector<BaseAddress::Ptr>& addrs, std::vector<BaseAddress::Ptr>& fails/*, bool ssl*/) {
    if (!GetIsInit()) {
        return false;
    }
//    ssl_ = ssl;
    for (const auto& addr : addrs) {
        auto sock = Socket::CreateTCP(addr);
        if (!sock) {
            HSBY_LOG_SYSTEM_WARN << "Socket::CreateTCP error, " << HSBY_FUNC_ERROR_WITH_ARG_EXP(addr->ToString());
            fails.push_back(addr);
            continue;
        }
        if (!sock->Bind(addr)) {
            HSBY_LOG_SYSTEM_WARN << "Socket::Bind error, " << HSBY_FUNC_ERROR_WITH_ARG_EXP(addr->ToString(), sock->ToString());
            fails.push_back(addr);
            continue;
        }
        if (!sock->Listen()) {
            HSBY_LOG_SYSTEM_WARN << "Socket::Listen error, " << HSBY_FUNC_ERROR_WITH_ARG_EXP(addr->ToString(), sock->ToString());
            fails.push_back(addr);
            continue;
        }
        sockets_.push_back(sock);
    }

    if (!fails.empty()) {
        sockets_.clear();
        return false;
    }
//
//    for (const auto& socket : sockets_) {
//        HSBY_LOG_SYSTEM_INFO << HSBY_VARS_EXP(type_, name_, ssl_, socket->ToString());
//    }

    return true;
}

bool TcpServer::Start() {
    if (!GetIsInit()) {
        return false;
    }
    if (!GetIsStop()) {
        return true;
    }
    SetIsStop(false);

    // 开始接受连接
    for (const auto& socket : sockets_) {
        accept_worker_->AddTask(std::bind(&TcpServer::OnAccept, shared_from_this(), socket));
    }
    return true;
}

void TcpServer::Stop() {
    if (!GetIsInit()) {
        return;
    }
    SetIsStop(true);
    auto self = shared_from_this();
    accept_worker_->AddTask([this, self]() {
        for (const auto &socket: sockets_) {
//            socket->CancelAll();
            socket->Close();
        }
        sockets_.clear();
    });
}

void TcpServer::ClientHandle(Socket::Ptr client) {
    HSBY_LOG_SYSTEM_INFO << "handle client" << HSBY_VARS_EXP(client->ToString());
    std::string recv_buf;
    while (client->Recv(recv_buf) > 0) {
        if (recv_buf == "0000") {
            Stop();
            break;
        }
    }
}

void TcpServer::OnAccept(Socket::Ptr socket) {
    //HSBY_LOG_SYSTEM_DEBUG << "begin OnAccept";
    while(!GetIsStop()) {
        auto client = socket->Accept();
        if (!client) {
            HSBY_LOG_SYSTEM_WARN << "accept client null";
            continue;
        }
        worker_->AddTask(std::bind(&TcpServer::ClientHandle, shared_from_this(), client));
    }
}

}//namespace hsby
